{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "DkA0Fobtb9dM"
   },
   "source": [
    "##### Copyright 2022 The Cirq Developers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "cellView": "form",
    "id": "tUshu7YfcAAW"
   },
   "outputs": [],
   "source": [
    "# @title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "# https://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "0_WkiXErntE5"
   },
   "source": [
    "# QVM Stabilizer Example"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "BODT5jJI4dZI"
   },
   "source": [
    "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://quantumai.google/cirq/simulate/qvm_stabilizer_example\"><img src=\"https://quantumai.google/site-assets/images/buttons/quantumai_logo_1x.png\" />View on QuantumAI</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/quantumlib/Cirq/blob/main/docs/simulate/qvm_stabilizer_example.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/colab_logo_1x.png\" />Run in Google Colab</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://github.com/quantumlib/Cirq/blob/main/docs/simulate/qvm_stabilizer_example.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/github_logo_1x.png\" />View source on GitHub</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a href=\"https://storage.googleapis.com/tensorflow_docs/Cirq/docs/simulate/qvm_stabilizer_example.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/download_icon_1x.png\" />Download notebook</a>\n",
    "  </td>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5d5f1638ebdf"
   },
   "source": [
    "This notebook demonstrates how to use a [Quantum Virtual Machine](./quantum_virtual_machine.ipynb) with larger, more elaborate circuits to demonstrate [stabilizer](https://en.wikipedia.org/wiki/Stabilizer_code){:.external} circuits and how they can reveal hardware errors."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Lfira0gPf0Gd"
   },
   "source": [
    "## **Install** Cirq and qsim, Create **Quantum Virtual Machine**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "cellView": "form",
    "id": "zs5J6wAXqvtW"
   },
   "outputs": [],
   "source": [
    "# @title Install `cirq_google` and `qsimcirq`\n",
    "\n",
    "try:\n",
    "    import cirq\n",
    "    import cirq_google\n",
    "except ImportError:\n",
    "    print(\"installing cirq...\")\n",
    "    !pip install --quiet cirq-google\n",
    "    print(\"installed cirq.\")\n",
    "    import cirq\n",
    "    import cirq_google\n",
    "\n",
    "try:\n",
    "    import qsimcirq\n",
    "except ImportError:\n",
    "    print(\"installing qsimcirq...\")\n",
    "    !pip install --quiet qsimcirq\n",
    "    print(f\"installed qsimcirq.\")\n",
    "    import qsimcirq\n",
    "\n",
    "# Other modules used in this colab\n",
    "import matplotlib.pyplot as plt\n",
    "import time\n",
    "import random"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "cellView": "form",
    "id": "pbHCUPLpq5WE"
   },
   "outputs": [],
   "source": [
    "# @title Create Quantum Virtual Machine: Choose a processor (\"willow_pink\", \"rainbow\" or \"weber\")\n",
    "# (see cirq_google.engine.list_virtual_processors() for available names)\n",
    "processor_id = \"willow_pink\"  # @param {type:\"string\"}\n",
    "\n",
    "# Instantiate the engine.\n",
    "sim_engine = cirq_google.engine.create_default_noisy_quantum_virtual_machine(\n",
    "    processor_id=processor_id, simulator_class=qsimcirq.QSimSimulator\n",
    ")\n",
    "print(\n",
    "    \"Your quantum virtual machine\",\n",
    "    processor_id,\n",
    "    \"is ready, here is the qubit grid:\",\n",
    "    \"\\n========================\\n\",\n",
    ")\n",
    "print(sim_engine.get_processor(processor_id).get_device())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "UncGyI-egm8d"
   },
   "source": [
    "## **Introduction** to stabilizer measurements\n",
    "\n",
    "The following code blocks measure a Z stabilizer as described by [Fowler et al (2012)](https://arxiv.org/abs/1208.0928). This type of circuit is central to the field of quantum error correction via the idea of a [Stabilizer Code](https://en.wikipedia.org/wiki/Stabilizer_code){:.external}. \n",
    "\n",
    "![image.png]()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "jSH1HAz25W6G"
   },
   "source": [
    "This circuit is constructed such that the central \"measure\" qubit will be in the $|1\\rangle$ state if an odd number of the four surrounding \"data\" qubits (named a-d in the figure) have a bit-flip error (corresponding to an X gate)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Hh8gyQWM62zE"
   },
   "source": [
    "## Stabilizer measurements on a **small grid**\n",
    "\n",
    "The examples below demonstrate a single Z stabilizer, similar to the image above. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "QspgLC3WHGJf"
   },
   "source": [
    "### Without noise\n",
    "\n",
    "In a perfectly noiseless Z stabilizer, all qubits will remain in the $|0\\rangle$ state."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "FOitwZQvHBPQ"
   },
   "outputs": [],
   "source": [
    "data_qubits = [cirq.NamedQubit('data_' + str(x)) for x in 'abcd']\n",
    "measure_qubit = cirq.NamedQubit('_meas')\n",
    "stabilizer_circuit = cirq.Circuit(\n",
    "    *[cirq.CX(data_qubit, measure_qubit) for data_qubit in data_qubits],\n",
    "    cirq.measure(measure_qubit, key='meas'),\n",
    ")\n",
    "\n",
    "print(f'Z-stabilizer circuit:')\n",
    "print('========================')\n",
    "print(stabilizer_circuit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "xXHsAF5FIDcM"
   },
   "outputs": [],
   "source": [
    "simulator = cirq.Simulator()\n",
    "result = simulator.run(stabilizer_circuit, repetitions=100)\n",
    "cirq.plot_state_histogram(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5Zwhyvi3IqIC"
   },
   "source": [
    "### With fixed noise\n",
    "\n",
    "If one of the qubits is flipped, the measure qubit will also flip to match the parity of the data qubits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "J48W_of2Ir_p"
   },
   "outputs": [],
   "source": [
    "random_data_qubit = random.choice(data_qubits)\n",
    "stabilizer_circuit_with_error = cirq.X(random_data_qubit) + stabilizer_circuit\n",
    "\n",
    "print(f'Z-stabilizer circuit with single error:')\n",
    "print('========================')\n",
    "print(stabilizer_circuit_with_error)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "MtJdnKIxI2rc"
   },
   "outputs": [],
   "source": [
    "result = simulator.run(stabilizer_circuit_with_error, repetitions=100)\n",
    "cirq.plot_state_histogram(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "BZMxGdueKrLu"
   },
   "source": [
    "### With hardware noise on the QVM\n",
    "\n",
    "With hardware-like noise, the stabilizer circuit becomes much more interesting. An arbitrary error could occur at any point:\n",
    "\n",
    "*   On a data qubit before or after the CNOT\n",
    "*   On the measure qubit before or after the CNOTs\n",
    "*   On the measure qubit _between_ CNOTs\n",
    "*   Multiple errors in any combination of the above locations\n",
    "\n",
    "The only indication of that error comes from the output of the measure qubit. By creating a grid of stabilizers and observing how they change over time, it's possible to decode when and where errors occured and compensate for them.\n",
    "\n",
    "The example below only runs a single cycle of one Z stabilizer, so it can't pinpoint error precisely. However, by measuring the data qubits afterwards it's possible to guess at where the error(s) took place."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "VWx6GaiUKpkW"
   },
   "outputs": [],
   "source": [
    "# Add measurements to the data qubits.\n",
    "stabilizer_circuit_for_hardware = stabilizer_circuit + (\n",
    "    cirq.Moment(cirq.measure(data_qubit, key=str(data_qubit)[-1]) for data_qubit in data_qubits)\n",
    ")\n",
    "print(f'Z-stabilizer circuit with data measurement:')\n",
    "print('========================')\n",
    "print(stabilizer_circuit_for_hardware)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "X9SgEuPzfwbD"
   },
   "outputs": [],
   "source": [
    "# Device_stabilizer_plaquette is an X-shaped region of qubits\n",
    "# on the actual device.\n",
    "device_stabilizer_plaquette = [\n",
    "    cirq.GridQubit(5, 3),\n",
    "    cirq.GridQubit(5, 2),\n",
    "    cirq.GridQubit(4, 3),\n",
    "    cirq.GridQubit(5, 4),\n",
    "    cirq.GridQubit(6, 3),\n",
    "]\n",
    "\n",
    "if processor_id == \"willow_pink\":\n",
    "    target_gateset = cirq.CZTargetGateset()\n",
    "else:\n",
    "    target_gateset = cirq.SqrtIswapTargetGateset()\n",
    "\n",
    "# Translate the circuit to a suitable gate set.\n",
    "test_stabilizer_circuit = cirq.optimize_for_target_gateset(\n",
    "    stabilizer_circuit_for_hardware,\n",
    "    context=cirq.TransformerContext(deep=True),\n",
    "    gateset=target_gateset,\n",
    ")\n",
    "# Map circuit qubits to hardware ones.\n",
    "qubit_map = dict(zip([measure_qubit] + data_qubits, device_stabilizer_plaquette))\n",
    "# Re-map the circuit to the hardware qubits.\n",
    "test_stabilizer_circuit = test_stabilizer_circuit.transform_qubits(lambda q: qubit_map[q])\n",
    "print(f'Z-stabilizer circuit optimized for {processor_id}:')\n",
    "print('========================')\n",
    "print(test_stabilizer_circuit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "JiUTetihmEA8"
   },
   "outputs": [],
   "source": [
    "# Run for 1k repetitions.\n",
    "repetitions = 1000\n",
    "start = time.time()\n",
    "results = sim_engine.get_sampler(processor_id).run(test_stabilizer_circuit, repetitions=repetitions)\n",
    "elapsed = time.time() - start\n",
    "print(f'{repetitions} repetitions completed in {elapsed:.03f}s')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "c6lmcI_ID7zp"
   },
   "source": [
    "Each result in the histogram below corresponds to a different set of possible errors. Below are some of the most likely cases for each measured result, or \"syndrome\", but there are many other possible cases not listed.\n",
    "\n",
    "*   No flips (`0_0000`) could be no error, or two errors on the same qubit.\n",
    "*   A single data flip (e.g. `0_1000`) could be a post-CNOT data error, or a pre-CNOT data error and a measurement error.\n",
    "*   A data flip and a measure flip (e.g. `1_1000`) could be a pre-CNOT data error or post-CNOT errors on both flipped qubits.\n",
    "*   Two data flips (e.g. `0_1100`) could be pre-CNOT or post-CNOT errors on both flipped qubits.\n",
    "\n",
    "...and so on, for more unusual cases."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "ydV-1HmnLHT9"
   },
   "outputs": [],
   "source": [
    "# A labeling function.\n",
    "def fold_func(bits) -> str:\n",
    "    suffix = \"\".join(map(str, [bits[i][0] for i in range(1, 5)]))\n",
    "    return f\"{bits[0][0]}_{suffix}\"\n",
    "\n",
    "\n",
    "hist = results.multi_measurement_histogram(keys=['meas'] + list('abcd'), fold_func=fold_func)\n",
    "\n",
    "print(\"Results (<meas>_<data>)\")\n",
    "ax = cirq.plot_state_histogram(hist)\n",
    "plt.setp(ax.get_xticklabels(), rotation=30, horizontalalignment='right');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "6XgoJWPaH5Qi"
   },
   "source": [
    "As a final exercise on this circuit, it's possible to display a 2D heatmap of measurement results. This will show which qubits measured a $|1\\rangle$ most often; on a hardware device, this could be used to highlight the performance of specific qubits. See [Heatmaps](../noise/heatmaps.ipynb) for more on visualizing error."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "7NIqBbdWkrMQ"
   },
   "outputs": [],
   "source": [
    "meas_map = {qubit_map[measure_qubit]: sum(results.measurements['meas']) / repetitions}\n",
    "\n",
    "data_map = {\n",
    "    qubit_map[dq]: sum(results.measurements[str(dq)[-1]]) / repetitions for dq in data_qubits\n",
    "}\n",
    "\n",
    "heatmap = cirq.Heatmap({**meas_map, **data_map})\n",
    "heatmap.plot();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "CERJOdfP7Ctx"
   },
   "source": [
    "## Stabilizer measurements on a **large grid**\n",
    "\n",
    "The next examples scale up the stabilizer grid to a 2x3 block of three Z stabilizers and three X stabilizers. Combining both stabilizer types allows many types of error to be detected and compensated for, although some ambiguity still remains. It also manually maps the circuit to the hardware qubits.\n",
    "\n",
    "A real logical qubit would require many more stabilizers to be fault-tolerant; however, this toy example is already near the upper bound of what a full statevector simulator can simulate on personal-level computers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "g__a69njShB_"
   },
   "outputs": [],
   "source": [
    "# Consider the following grid, where numbers represent\n",
    "# measure qubits and letters represent data qubits:\n",
    "#\n",
    "#     A\n",
    "#    B0C\n",
    "#   D1E2F\n",
    "#    G3H4J\n",
    "#     K5L\n",
    "#      M\n",
    "#\n",
    "# Center Z-plaquettes on [0, 3, 4] and\n",
    "# X-plaquettes on [1, 2, 5]\n",
    "\n",
    "# Instantiate the alphabetical data qubits and numerical measurement qubits.\n",
    "grid_data_qubits = {x: cirq.NamedQubit(x) for x in 'ABCDEFGHJKLM'}\n",
    "grid_meas_qubits = {x: cirq.NamedQubit(str(x)) for x in range(6)}\n",
    "\n",
    "# Build the diamond shaped stabilizer circuit from six layered smaller stabilizers.\n",
    "stabilizer_grid_circuit = cirq.Circuit(\n",
    "    cirq.H.on_each(grid_meas_qubits[x] for x in [1, 2, 5]),\n",
    "    *[cirq.CX(grid_data_qubits[x], grid_meas_qubits[0]) for x in 'ABCE'],\n",
    "    *[cirq.CX(grid_meas_qubits[1], grid_data_qubits[x]) for x in 'BDEG'],\n",
    "    *[cirq.CX(grid_meas_qubits[2], grid_data_qubits[x]) for x in 'CEFH'],\n",
    "    *[cirq.CX(grid_data_qubits[x], grid_meas_qubits[3]) for x in 'EGHK'],\n",
    "    *[cirq.CX(grid_data_qubits[x], grid_meas_qubits[4]) for x in 'FHJL'],\n",
    "    *[cirq.CX(grid_meas_qubits[5], grid_data_qubits[x]) for x in 'HKLM'],\n",
    "    cirq.H.on_each(grid_meas_qubits[x] for x in [1, 2, 5]),\n",
    "    *[cirq.measure(mq) for mq in grid_meas_qubits.values()],\n",
    "    *[cirq.measure(dq) for dq in grid_data_qubits.values()],\n",
    ")\n",
    "# Map the named qubits of the stabilizer circuit to GridQubits on the hardware.\n",
    "qubit_map = {\n",
    "    cirq.NamedQubit('A'): cirq.GridQubit(4, 3),\n",
    "    cirq.NamedQubit('B'): cirq.GridQubit(5, 2),\n",
    "    cirq.NamedQubit('0'): cirq.GridQubit(5, 3),\n",
    "    cirq.NamedQubit('C'): cirq.GridQubit(5, 4),\n",
    "    cirq.NamedQubit('D'): cirq.GridQubit(6, 1),\n",
    "    cirq.NamedQubit('1'): cirq.GridQubit(6, 2),\n",
    "    cirq.NamedQubit('E'): cirq.GridQubit(6, 3),\n",
    "    cirq.NamedQubit('2'): cirq.GridQubit(6, 4),\n",
    "    cirq.NamedQubit('F'): cirq.GridQubit(6, 5),\n",
    "    cirq.NamedQubit('G'): cirq.GridQubit(7, 2),\n",
    "    cirq.NamedQubit('3'): cirq.GridQubit(7, 3),\n",
    "    cirq.NamedQubit('H'): cirq.GridQubit(7, 4),\n",
    "    cirq.NamedQubit('4'): cirq.GridQubit(7, 5),\n",
    "    cirq.NamedQubit('J'): cirq.GridQubit(7, 6),\n",
    "    cirq.NamedQubit('K'): cirq.GridQubit(8, 3),\n",
    "    cirq.NamedQubit('5'): cirq.GridQubit(8, 4),\n",
    "    cirq.NamedQubit('L'): cirq.GridQubit(8, 5),\n",
    "    cirq.NamedQubit('M'): cirq.GridQubit(9, 4),\n",
    "}\n",
    "stabilizer_grid_circuit = stabilizer_grid_circuit.transform_qubits(lambda q: qubit_map[q])\n",
    "print(stabilizer_grid_circuit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ljEDw02_kzTT"
   },
   "source": [
    "### [Optional] View 3D circuit\n",
    "\n",
    "Large circuits that are mapped to grids are suitable to be visualized in 3D with `cirq_web`, if you find it useful, as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "BsSR-ndEi0Tq"
   },
   "outputs": [],
   "source": [
    "!pip install --quiet cirq-web\n",
    "import cirq_web\n",
    "\n",
    "circuit_vis = cirq_web.Circuit3D(stabilizer_grid_circuit)\n",
    "display(circuit_vis)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "3T0UsKjVJZTb"
   },
   "source": [
    "### Without noise\n",
    "\n",
    "The noiseless version of the larger grid is slightly more exciting than the small grid example: the X measure qubits will measure a random state since their neighbors are initialized in the Z basis. However, subsequent measurements will remain consistent.\n",
    "\n",
    "The example below runs a single cycle of the 2x3 grid 100 times, then does a Z-basis measurement of all data qubits. Since each of these is a separate execution of the circuit, no correlation is expected between repetitions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "2YwmAqBJSPHM"
   },
   "outputs": [],
   "source": [
    "noiseless_sim = qsimcirq.QSimSimulator()\n",
    "\n",
    "repetitions = 100\n",
    "start = time.time()\n",
    "results = noiseless_sim.run(stabilizer_grid_circuit, repetitions=repetitions)\n",
    "elapsed = time.time() - start\n",
    "print(f'{repetitions} repetitions completed in {elapsed:.03f}s')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "o1D_wxTCScFf"
   },
   "outputs": [],
   "source": [
    "# Set to view results from each repetition.\n",
    "repetition = 0  # @param {type:\"number\"}\n",
    "meas_map = {\n",
    "    qubit_map[q]: results.measurements[str(q)][repetition] for q in grid_meas_qubits.values()\n",
    "}\n",
    "\n",
    "data_map = {\n",
    "    qubit_map[q]: results.measurements[str(q)][repetition] for q in grid_data_qubits.values()\n",
    "}\n",
    "\n",
    "heatmap = cirq.Heatmap({**meas_map, **data_map})\n",
    "heatmap.plot();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "2PamsJlJSHhd"
   },
   "source": [
    "### With hardware noise on the QVM\n",
    "\n",
    "Adding in hardware-like noise means that subsequent cycles of a stabilizer might disagree with one another. These inconsistencies can be interpreted as various error modes, which can be decoded to compensate for the errors observed.\n",
    "\n",
    "Decoding stabilizer error is a complex topic not covered here, but the pre-decoding results and data qubit measurements shown below may shed some light on how to approach this process."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "BQV2XcR5gd6X"
   },
   "outputs": [],
   "source": [
    "test_stabilizer_grid_circuit = cirq.optimize_for_target_gateset(\n",
    "    cirq.Circuit(cirq.decompose(stabilizer_grid_circuit)),\n",
    "    context=cirq.TransformerContext(deep=True),\n",
    "    gateset=target_gateset,\n",
    ")\n",
    "print(test_stabilizer_grid_circuit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "h3T2WqzibNfg"
   },
   "outputs": [],
   "source": [
    "repetitions = 100\n",
    "start = time.time()\n",
    "results = sim_engine.get_sampler(processor_id).run(\n",
    "    test_stabilizer_grid_circuit, repetitions=repetitions\n",
    ")\n",
    "elapsed = time.time() - start\n",
    "print(f'{repetitions} repetitions completed in {elapsed:.03f}s')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "5dP0h-OCYJjL"
   },
   "outputs": [],
   "source": [
    "# Set to view results from each repetition.\n",
    "repetition = 0  # @param {type:\"number\"}\n",
    "meas_map = {\n",
    "    qubit_map[q]: results.measurements[str(q)][repetition] for q in grid_meas_qubits.values()\n",
    "}\n",
    "\n",
    "data_map = {\n",
    "    qubit_map[q]: results.measurements[str(q)][repetition] for q in grid_data_qubits.values()\n",
    "}\n",
    "\n",
    "heatmap = cirq.Heatmap({**meas_map, **data_map})\n",
    "heatmap.plot();"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "qvm_stabilizer_example.ipynb",
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
